/*
 * @Author: xiguan
 * @Email: xiguan.teng@qq.com
 * @Version: 1.0
 * @Date: 2022-07-29 15:19:30
 * @LastEditTime: 2022-07-31 12:21:07
 */


#ifndef _DEQUEMY_H_
#define _DEQUEMY_H_

#include "AllocatorMy.h"
#include "IteratorMy.h"
#include "ReverseIteratorMy.h"
#include "UtilityMy.h"

namespace MySTL{

    template<class T, class Alloc = allocator<T>>
    class deque;

    namespace Realize{
        // class of deque's iterator
        template<class T>
        class _deque_iterator : public iterator<bidirectional_iterator_tag, T>{
        private:
            template<class Tf, class Alloc>
            friend class ::MySTL::deque;

        private:
            typedef const ::MySTL::deque<T> *cntrPtr;
            size_t                          mapIndex_;
            T                               *cur_;
            cntrPtr                         container_;

        public:
            // big three
            _deque_iterator() : mapIndex_(-1), cur_(0), container_(0){}
            _deque_iterator( size_t index, T *ptr, cntrPtr container )
                : mapIndex_(index), cur_(ptr), container_(container){}
            _deque_iterator( const _deque_iterator &it )
                : mapIndex_(it.mapIndex_), cur_(it.cur_), container_(it.container_){}
        
        public:
            _deque_iterator &operator=( const _deque_iterator &it );
            void swap( _deque_iterator &it );
            typename MySTL::iterator<bidirectional_iterator_tag, T>::reference operator*() {
                return *cur_;
            }
            const typename MySTL::iterator<bidirectional_iterator_tag, T>::reference operator*() const {
                return *cur_;
            }
            typename MySTL::iterator<bidirectional_iterator_tag, T>::pointer operator->(){
                return &(operator*());
            }
            const typename MySTL::iterator<bidirectional_iterator_tag, T>::pointer operator->() const {
                return &(operator*());
            }
            _deque_iterator &operator++();
            _deque_iterator operator++(int);
            _deque_iterator &operator--();
            _deque_iterator operator--(int);
            bool operator==( const _deque_iterator &it ) const;
            bool operator!=( const _deque_iterator &it ) const;

        private:
            T *getBuckTail( size_t mapIndex ) const;
            T *getBuckHead( size_t mapIndex ) const;
            size_t getBuckSize() const;

        public:
            template<class Tf>
            friend _deque_iterator<Tf> operator+( const _deque_iterator<Tf> &it, typename _deque_iterator<Tf>::difference_type n );
            template<class Tf>
            friend _deque_iterator<Tf> operator+( typename _deque_iterator<Tf>::difference_type n, const _deque_iterator<Tf> &it );
            template<class Tf>
            friend _deque_iterator<Tf> operator-( const _deque_iterator<Tf> &it, typename _deque_iterator<Tf>::difference_type n );
            template<class Tf>
            friend _deque_iterator<Tf> operator-( typename _deque_iterator::difference_type n, const _deque_iterator<Tf> &it );
            template<class Tf>
            friend typename _deque_iterator<Tf>::difference_type operator-( const _deque_iterator<Tf> &it1, const _deque_iterator<Tf> &it2 );
            
            template<class Tf>
            friend void swap( _deque_iterator<Tf> &lhs, _deque_iterator<Tf> &rhs );
        }; 
    }


    // class of deque
    template<class T, class Alloc>
    class deque{
    private:
        template<class Tf>
        friend class ::MySTL::Realize::_deque_iterator;

    public:
        typedef T                                   value_type;
        typedef Realize::_deque_iterator<T>         iterator;
        typedef Realize::_deque_iterator<const T>   const_iterator;
        typedef T                                   &reference;
        typedef const reference                     const_reference;
        typedef size_t                              size_type;
        typedef ptrdiff_t                           difference_type;
        typedef Alloc                               allocator_type;

    private:
        typedef Alloc       dataAllocator;
        enum class EBucksSize{ BUCKSIZE = 64 };
    
    private:
        iterator beg_, end_;
        size_type mapSize_;
        T **map_;
    
    public:
        deque();
        explicit deque( size_type n, const value_type &val = value_type() );
        template<class InputIterator>
        deque( InputIterator first, InputIterator last );
        deque( const deque &x );
        ~deque();
    public:
        deque &operator=( const deque &x );
        deque &operator=( deque &&x );
    
    public:
        iterator begin();
        iterator end();
        iterator begin() const;
        iterator end() const;
    
    public:
        size_type size() const {
            return end() - begin();
        }
        bool empty() const {
            return begin() == end();
        }

        reference operator[]( size_type n );
        reference front();
        reference back();
        const_reference operator[]( size_type n ) const;
        const_reference front() const;
        const_reference back() const;
    
        void push_back( const value_type &val );
        void push_front( const value_type &val );
        void pop_back();
        void pop_front();
        void swap( deque &x );
        void clear();
    
    private:
        T *getANewBuck();
        T **getANewMap( const size_t size );
        size_t getNewMapSize( const size_t size );
        size_t getBuckSize() const;
        void init();
        bool back_full() const;
        bool front_full() const;
        void deque_aux( size_t n, const value_type &val, std::true_type );
        template<class Iterator>
        void deque_aux( Iterator first, Iterator last, std::false_type );
        void reallocateAndCopy();
    
    public:
        template<class Tf, class Allocf>
        friend bool operator==( const deque<Tf, Allocf> &lhs, const deque<Tf, Allocf> &rhs );
        template<class Tf, class Allocf>
        friend bool operator!=( const deque<Tf, Allocf> &lhs, const deque<Tf, Allocf> &rhs );
        template<class Tf, class Allocf>
        friend void swap( deque<Tf, Allocf> &x, deque<Tf, Allocf> &y );

    };


}

#include "./Realize/DequeMy.impl.h"

#endif